/**
 * Created by IntelliJ IDEA.
 * User: Taras_Brzezinsky
 * Date: 8/23/11
 * Time: 5:49 PM
 * To change this template use File | Settings | File Templates.
 */


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.IOException;
import java.util.*;

public class TaskA extends Thread {
    public TaskA() {
        this.input = new BufferedReader(new InputStreamReader(System.in));
        this.output = new PrintWriter(System.out);
        this.setPriority(Thread.MAX_PRIORITY);
    }

    static class Edge {
        int to;
        int cost;
        public Edge(int to, int cost) {
            this.to = to;
            this.cost = cost;
        }
    }
    static class Answer implements Comparable<Answer> {
        int tank, tap, cost;
        public Answer(int tank, int tap, int cost) {
            this.tank = tank;
            this.tap = tap;
            this.cost = cost;
        }
        public int compareTo(Answer o) {
            return this.tank - o.tank;
        }
        public String toString() {
            String result = Integer.toString(tank + 1) + " " + Integer.toString(tap + 1) + " " + Integer.toString(cost);
            return result;
        }
    }

    private void solve() throws Throwable {
        int n = nextInt();
        int p = nextInt();
        g = new ArrayList [n];
        int []to = new int[n];
        int []fr = new int[n];
        for (int i = 0; i < n; ++i) {
            g[i] = new ArrayList<Edge>();
        }
        for (int i = 0; i < p; ++i) {
            int a = nextInt() - 1, b = nextInt() - 1, c = nextInt();
            g[a].add(new Edge(b, c));
            ++fr[a];
            ++to[b];
        }
        ArrayList<Answer> result = new ArrayList<Answer>();
         Queue<Integer> where = new ArrayDeque<Integer>();
        Queue<Integer> cost = new ArrayDeque<Integer>();
        for (int i = 0; i < n; ++i) {
            where.clear();
            cost.clear();
            if (to[i] == 0) {
                where.add(i);
                cost.add(Integer.MAX_VALUE);
                while (!where.isEmpty()) {
                    int from = where.poll(), current = cost.poll();
                    for (Edge temp : g[from]) {
                        if (g[temp.to].size() == 0) {
                            result.add(new Answer(i, temp.to, Math.min(current, temp.cost)));
                        } else {
                            where.add(temp.to);
                            cost.add(Math.min(current, temp.cost));
                        }
                    }
                }
            }
        }
        Collections.sort(result);
        output.println(result.size());
        for (Answer current : result) {
            output.println(current);
        }
    }

    public void run() {
        try {
            solve();
        } catch (Throwable e) {
            System.err.println(e.getMessage());
            e.printStackTrace();
            System.exit(666);
        } finally {
            output.flush();
            output.close();
        }
    }

    public static void main(String[] args) {
        new TaskA().start();
    }

    private int nextInt() throws IOException {
        return Integer.parseInt(nextToken());
    }

    private long nextLong() throws IOException {
        return Long.parseLong(nextToken());
    }

    private double nextDouble() throws IOException {
        return Double.parseDouble(nextToken());
    }

    private String nextToken() throws IOException {
        while (tokens == null || !tokens.hasMoreTokens()) {
            tokens = new StringTokenizer(input.readLine());
        }
        return tokens.nextToken();
    }
    ArrayList<Edge> g[];
    private BufferedReader input;
    private PrintWriter output;
    private StringTokenizer tokens = null;
}
